#include "util/coding.h"

namespace leveldb {
void PutFixed32(std::string *dst, uint32_t value) {
    char buf[sizeof(value)];
    EncodeFixed32(buf, value);
    dst->append(buf, sizeof(buf));
}

void PutFixed64(std::string *dst, uint64_t value) {
    char buf[sizeof(value)];
    EncodeFixed64(buf, value);
    dst->append(buf, sizeof(buf));
}

char *EncodeVarint32(char *dst, uint32_t value) {
    // 首先还是cast，把char转成uint8
    uint8_t *ptr = reinterpret_cast<uint8_t *>(dst);
    static const int B = 128;
    if (value < (1 << 7)) { // 此时用七位可以放下，最高位置0
        *(ptr++) = value;
    } else if (value < (1 << 14)) {
        // 此时需要7到14位表示下来，第一个字节最高位1，第二个字节最高位0
        *(ptr++) = value | B;  //拿到低八位，强制最高位为1
        *(ptr++) = value >> 7; //拿到高位的七个
    } else if (value < (1 << 21)) {
        *(ptr++) = value | B;
        *(ptr++) = (value >> 7) | B;
        *(ptr++) = value >> 14;
    } else if (value < (1 << 28)) {
        *(ptr++) = value | B;
        *(ptr++) = (value >> 7) | B;
        *(ptr++) = (value >> 14) | B;
        *(ptr++) = value >> 21;
    } else {
        *(ptr++) = value | B;
        *(ptr++) = (value >> 7) | B;
        *(ptr++) = (value >> 14) | B;
        *(ptr++) = (value >> 21) | B;
        *(ptr++) = value >> 28;
    }
    // 处理完毕
    return reinterpret_cast<char *>(ptr);
    // 返回的是末尾的指针，可以和dst相减获取编码长度
}

void PutVarint32(std::string *dst, uint32_t value) {
    char buf[5];
    char *ptr = EncodeVarint32(buf, value);
    dst->append(buf, ptr - buf);
}

char *EncodeVarint64(char *dst, uint64_t v) {
    static const int B = 128;
    uint8_t *ptr = reinterpret_cast<uint8_t *>(dst);
    while (v >= B) {
        *(ptr++) = v | B;
        v >>= 7;
    }
    *(ptr++) = static_cast<uint8_t>(v);
    return reinterpret_cast<char *>(ptr);
}

void PutVarint64(std::string *dst, uint64_t value) {
    char buf[10];
    char *ptr = EncodeVarint64(buf, value);
    dst->append(buf, ptr - buf);
}

void PutLengthPrefixedSlice(std::string *dst, const Slice &value) {
    PutVarint32(dst, value.size());          // 对长度进行编码
    dst->append(value.data(), value.size()); // 再把数据放到里面去
}

int VarintLength(uint64_t v) {
    int res = 1;
    while (v >= 128) {
        v >>= 7;
        res++;
    }
    return res;
}

const char *GetVarint32PtrFallback(const char *p, const char *limit,
                                   uint32_t *value) {
    uint32_t res = 0;
    for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7) {
        uint32_t byte = *(reinterpret_cast<const uint8_t *>(p));
        p++;
        if (byte & 128) {
            res |= ((byte & 127) << shift);
        } else {
            res |= (byte << shift);
            *value = res;
            return reinterpret_cast<const char *>(p);
        }
    }
    return nullptr;
}
//解码函数入口，主要判断内存是否超出
bool GetVarint32(Slice *input, uint32_t *value) {
    const char *p = input->data();
    const char *limit = p + input->size();
    const char *q = GetVarint32Ptr(p, limit, value);
    if (q == nullptr) {
        return false;
    } else {
        *input = Slice(q, limit - q);
        return true;
    }
}

const char *GetVarint64Ptr(const char *p, const char *limit, uint64_t *value) {
    uint64_t res = 0;
    for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7) {
        uint64_t byte = *(reinterpret_cast<const uint8_t *>(p));
        p++;
        if (byte & 128) {
            res |= ((byte & 127) << shift);
        } else {
            res |= (byte << shift);
            *value = res;
            return reinterpret_cast<const char *>(p);
        }
    }
    return nullptr;
}

//将编码后的 string 中的长度信息去除，提出出原始 string。
bool GetLengthPrefixedSlice(Slice *input, Slice *result) {

    uint32_t len;
    if (GetVarint32(input, &len) && input->size() >= len) {
        *result = Slice(input->data(), len);
        input->remove_prefix(len);
        return true;
    } else {
        return false;
    }
}

} // namespace leveldb